/*****************************************************************************
 *	      ______
 *	    /   _   \   _   __    ______
 *	   /  /_ /  / /  //__ / /   _   \
 *	  /   ____ / /   /     /  /  /  /
 *	 /  /       /  /      /  /_ /  /
 *	/_ /       /_ /       \ _____ /
 *	           ______
 *	         /  ____ /  ______     _   __     _    ______
 *	        /  /___   /   _   \  /  //_  \  /_ / /   _   \
 *	       _\___   \ /  /  /  / /   / /  / /  / /  /  /_ /
 *	     /  /_ /  / /  /_ /  / /  /  /  / /  / /  /____ 
 *	     \______ /  \ _____ / /_ /  /_ / /_ /  \ ______/
 *	
 *	LIMP
 *	
 *	
 *	ProSonic Engine
 *	Created by Damian Grove
 *	
 *	Programmed in C
 *	Compiled with DJGPP - GCC 2.952
 *	Libraries used:
 *		- Allegro - 3.9.34	http://www.talula.demon.co.uk/allegro/
 *		- DUMB - 0.9.3		http://dumb.sourceforge.net/
 *	
 *****************************************************************************/

#include	<stdio.h>
#include	<string.h>



// TO-DO LIST:
// - Update HEADER code
// - Might need to update BMAP (to incorporate the "plane" bit)



// Sonic the Hedgehog
#define		S1_TILES		0x2478
#define		S1_MAP			0xC878
#define		S1_BLOCKS		0xD478
#define		S1_SOLIDITY		0x0 // ?
#define		S1_RINGS		0x0 // ? not stored in S1 RAM
#define		S1_PALETTE		0x11F78
#define		S1_WPALETTE		0x11E78

// Sonic the Hedgehog 2 (commercial)
#define		S2_TILES		0x2478
#define		S2_MAP			0xA478
#define		S2_BLOCKS		0xB478
#define		S2_SOLIDITY		0xFA78
#define		S2_RINGS		0x10C80
#define		S2_PALETTE		0x11F78
#define		S2_WPALETTE		0x11478

// Sonic the Hedgehog 2 (1998 beta)
#define		S2B_TILES		0x2478
#define		S2B_MAP			0xA478
#define		S2B_BLOCKS		0xB478
#define		S2B_SOLIDITY	0xF478	// different from S2
#define		S2B_RINGS		0x10C80 // making assumption here -- never actually tested!
#define		S2B_PALETTE		0x11F78
#define		S2B_WPALETTE	0x11FF8

// Sonic the Hedgehog 2 (2006 beta)
// HAVEN'T RESEARCHED THIS YET!!

#define		SPRITES			0x12478

#define		VALUE_ZONE		0x12288
#define		VALUE_ACT		0x12289

int		TILES;
int		MAP;
int		BLOCKS;
int		SOLIDITY;
int		RINGS;
int		PALETTE;	// Regular palette
int		WPALETTE;	// Underwater palette

enum SonicGame
{
	SONIC1,
	SONIC2,
	SONIC2BETA
};

int		Game = SONIC2;	// Make this user-selectable in the future

enum DrawProperty
{
	NORMAL,
	MIRROR,
	FLIP,
	ROTATE
};


unsigned char	Byte1;
unsigned char	Byte2;
unsigned char	Byte3;
unsigned char	Byte4;
unsigned short	Word1;
unsigned short	Word2;
unsigned short	Word3;
unsigned short	Word4;
unsigned short	Word5;
unsigned int	DWord1;
unsigned int	DWord2;
int			test1;
int			test2;
int			Block;
int			Tile;

char priority[0x400];


//int			CreateHeader();		// PZF file header
int			CreateBATT();
int			CreateBLOCK();
int			CreateBMAP();
int			CreateBSOL();
int			CreateOBJ();
int			CreatePAL();
int			CreateTMAP();


char		nameSavestate[128];
char		nameROM[128];

char		ZonePrefix[6];	// We include space for 2 extra bytes to detect prefix errors
char		BMAPName[13];
char		TMAPName[13];
char		PALName[13];
char		OBJName[13];
char		BSOLName[13];
char		BATTName[13];
char		BDATName[13];
char		BLOCKName[13];

FILE		*gssSavestate;		// Genecyst savestate
FILE		*binROM;			// Sega Genesis ROM
FILE		*datLimp2;			// Collision data taken from the Sonic 2 ROM
FILE		*pzfHeader;			// PZF file header to be created
FILE		*datBlockSlope;
FILE		*datBlockData;
FILE		*datBlocks;
FILE		*datBlockMap;
FILE		*datBlockSolid;
FILE		*datObjects;
FILE		*datPalette;
FILE		*datTileMap;

char		PaletteData[192];



int main()
{
	printf("LIMP\nProSonic level importer!\n\n");

	printf("Type the name of the savestate you wish to use: ");
	fgets(nameSavestate, 128, stdin);
	nameSavestate[strlen(nameSavestate) - 1] = '\0';
	if(fopen(nameSavestate, "rb") == NULL){
		printf("\n\nERROR 1: Cannot open file");
		return 0;
	}
	
	printf("Type the name of the ROM you wish to use: ");
	fgets(nameROM, 128, stdin);
	nameROM[strlen(nameROM) - 1] = '\0';
	if(fopen(nameROM, "rb") == NULL){
		printf("\n\nERROR 2: Cannot open file");
		return 0;
	}


	printf("Type the zone prefix you want to use: ");
	fgets(ZonePrefix, 6, stdin);
	printf("\n");
	if(strlen(ZonePrefix) > 4)
	{
		printf("\n\nERROR 3: Prefix cannot exceed 3 characters");
		return 0;
	}
	else
	{
		ZonePrefix[strlen(ZonePrefix) - 1] = '\0';
		strcpy(BMAPName, ZonePrefix);
		strcat(BMAPName, "BMAP.DAT");
		strcpy(TMAPName, ZonePrefix);
		strcat(TMAPName, "TMAP.DAT");
		strcpy(BSOLName, ZonePrefix);
		strcat(BSOLName, "BSOL.DAT");
		strcpy(BATTName, ZonePrefix);
		strcat(BATTName, "BATT.DAT");
		strcpy(BDATName, ZonePrefix);
		strcat(BDATName, "BDAT.DAT");
		strcpy(OBJName, ZonePrefix);
		strcat(OBJName, "OBJ.DAT");
		strcpy(PALName, ZonePrefix);
		strcat(PALName, "PAL.DAT");
		strcpy(BLOCKName, ZonePrefix);
		strcat(BLOCKName, "BLOCK.DAT");
	}
	
	
	
	switch(Game)
	{
		case SONIC1:
			TILES = S1_TILES;
			MAP = S1_MAP;
			BLOCKS = S1_BLOCKS;
			SOLIDITY = S1_SOLIDITY;
			RINGS = S1_RINGS;
			PALETTE = S1_PALETTE;
			WPALETTE = S1_WPALETTE;
			break;
		case SONIC2:
			TILES = S2_TILES;
			MAP = S2_MAP;
			BLOCKS = S2_BLOCKS;
			SOLIDITY = S2_SOLIDITY;
			RINGS = S2_RINGS;
			PALETTE = S2_PALETTE;
			WPALETTE = S2_WPALETTE;
			break;
		case SONIC2BETA:
			TILES = S2B_TILES;
			MAP = S2B_MAP;
			BLOCKS = S2B_BLOCKS;
			SOLIDITY = S2B_SOLIDITY;
			RINGS = S2B_RINGS;
			PALETTE = S2B_PALETTE;
			WPALETTE = S2B_WPALETTE;
			break;
	}



	gssSavestate = fopen(nameSavestate, "rb");
	binROM = fopen(nameROM, "rb");
	datLimp2 = fopen("Limp2.dat", "rb");		// For Sonic 2

	//pzfHeader = fopen("HEADER.DAT", "w+b");
	datBlockSlope = fopen(BATTName, "w+b");
	datBlocks = fopen(BLOCKName, "w+b");
	datBlockMap = fopen(BMAPName, "w+b");
	datBlockSolid = fopen(BSOLName, "w+b");
	datBlockData = fopen(BDATName, "w+b");
	datObjects = fopen(OBJName, "w+b");
	datPalette = fopen(PALName, "w+b");
	datTileMap = fopen(TMAPName, "w+b");


	//CreateHeader();
	//printf("\n- PZF file header created");
	CreatePAL();
	printf("\n- Palette data created");
	CreateBLOCK();
	printf("\n- Block data created");
	CreateBMAP();
	if(Game == SONIC1)	CreateBMAP(); // Do twice for Sonic 1
	printf("\n- Block-map data created");
	CreateTMAP();
	printf("\n- Tile-map data created");
	CreateBSOL();
	printf("\n- Block solidity data created");
	CreateOBJ();
	printf("\n- Object layout data created");


	fclose(gssSavestate);
	fclose(binROM);
	//fclose(pzfHeader);
	fclose(datBlockSlope);
	fclose(datBlocks);
	fclose(datBlockMap);
	fclose(datBlockSolid);
	fclose(datBlockData);
	fclose(datObjects);
	fclose(datPalette);
	fclose(datTileMap);

	printf("\n\nFinished!");

	return 0;
}



/*int CreateHeader()
{
	char	TempFiller = 0;	// temporary variable to use for unused ones
	
	char	TimeZoneCount = 1;	// 1-4
	char	ActCount = 1;		// 1-8
	char	TileSize;		// 0 - 32, 1 - 64, 2 - 128, 3 - 256
	char	LevelName1[] = "UNTITLED        ";
	char	LevelName2[] = "UNTITLED        ";
	short	PlayerStartX1;
	short	PlayerStartY1;
	short	PlayerStartX2;	// unused
	short	PlayerStartY2;	// unused
	short	PlayerStartX3;	// unused
	short	PlayerStartY3;	// unused
	short	PlayerStartX4;	// unused
	short	PlayerStartY4;	// unused
	short	PlayerStartX5;	// unused
	short	PlayerStartY5;	// unused
	short	PlayerStartX6;	// unused
	short	PlayerStartY6;	// unused
	short	PlayerStartX7;	// unused
	short	PlayerStartY7;	// unused
	short	PlayerStartX8;	// unused
	short	PlayerStartY8;	// unused
	short	LevelSizeXL;	// X size from left
	short	LevelSizeXR;	// X size to right
	short	LevelSizeYT;	// Y size from top
	short	LevelSizeYB;	// Y size to bottom
	short	WaterHeight;
	char	TileColumns;	// unused
	char	TileRows;		// unused
	char	WaterEnable;
	char	Song1P;
	char	Song2P;
	//short	FilterDimL;		// Top filter dimension for plane L
	//short	FilterDimH;		// Top filter dimension for plane H
	//short	FilterDimB;		// Top filter dimension for plane B
	//char	FilterSpeedTL;	// Top filter plane L speed
	//char	FilterSpeedH~~~ finish this stuff later...
	//
	char	pzfNamePAL[] = "PALETTE 1       ";
	char	pzfNameWMAP[] = "WATER MAP 1     ";
	char	pzfNameBMAP[] = "BLOCK MAP 1     ";
	char	pzfNameBLOCK[] = "BLOCK ART 1     ";
	char	pzfNameBDAT[] = "BLOCK PLANES 1  ";
	char	pzfNameBATT[] = "SLOPE TABLE 1   ";
	char	pzfNameBSOL[] = "SOLIDITY 1      ";
	char	pzfNameTMAP[] = "TILE MAP 1      ";
	char	pzfNameFILTER[] = "FILTER 1        ";
	char	pzfNameOBJ[] = "OBJECT MAP 1    ";
	
	
	// Temporary stuff
	if(Game == SONIC1)
		TileSize = 3;	// 256x256
	else
		TileSize = 2;	// 128x128
	
	
	Byte1 = 'P';
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	Byte1 = 'Z';
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	Byte1 = 'F';
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	
	Byte1 = (TimeZoneCount << 4) + ActCount;
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	
	fwrite(&TileSize, sizeof(char), 1, pzfHeader);
	
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&LevelName1[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&LevelName2[Byte1], sizeof(char), 1, pzfHeader);
		
	fseek(gssSavestate, 0xD480, SEEK_SET);
	fread(&PlayerStartX1, sizeof(short), 1, gssSavestate);
	fwrite(&PlayerStartX1, sizeof(short), 1, pzfHeader);
	fseek(gssSavestate, 0xD484, SEEK_SET);
	fread(&PlayerStartY1, sizeof(short), 1, gssSavestate);
	fwrite(&PlayerStartY1, sizeof(short), 1, pzfHeader);
	
	fwrite(&PlayerStartX2, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartY2, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartX3, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartY3, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartX4, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartY4, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartX5, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartY5, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartX6, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartY6, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartX7, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartY7, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartX8, sizeof(short), 1, pzfHeader);
	fwrite(&PlayerStartY8, sizeof(short), 1, pzfHeader);
	
	fseek(gssSavestate, 0x11338, SEEK_SET);
	fread(&LevelSizeXL, sizeof(short), 1, gssSavestate);
	fread(&LevelSizeXR, sizeof(short), 1, gssSavestate);
	fread(&LevelSizeYT, sizeof(short), 1, gssSavestate);
	fread(&LevelSizeYB, sizeof(short), 1, gssSavestate);
	fwrite(&LevelSizeXL, sizeof(short), 1, pzfHeader);
	fwrite(&LevelSizeXR, sizeof(short), 1, pzfHeader);
	fwrite(&LevelSizeYT, sizeof(short), 1, pzfHeader);
	fwrite(&LevelSizeYB, sizeof(short), 1, pzfHeader);
	
	fseek(gssSavestate, 0x11AC0, SEEK_SET);
	fread(&WaterHeight, sizeof(short), 1, gssSavestate);
	fwrite(&WaterHeight, sizeof(short), 1, pzfHeader);
	
	fwrite(&TileColumns, sizeof(char), 1, pzfHeader);
	fwrite(&TileRows, sizeof(char), 1, pzfHeader);
	
	fseek(gssSavestate, 0x11AC4, SEEK_SET);
	fread(&WaterEnable, sizeof(char), 1, gssSavestate);
	fwrite(&WaterEnable, sizeof(char), 1, pzfHeader);
	
	fwrite(&Song1P, sizeof(char), 1, pzfHeader);
	fwrite(&Song2P, sizeof(char), 1, pzfHeader);
	
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	
	for(Byte1 = 0; Byte1 < 33; Byte1++)
		fwrite(&TempFiller, sizeof(char), 1, pzfHeader);
		
	Byte1 = 0x11;
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	Byte1 = 1;
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);
	fwrite(&Byte1, sizeof(char), 1, pzfHeader);

	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNamePAL[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameWMAP[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameBMAP[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameBLOCK[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameBDAT[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameBATT[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameBSOL[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameTMAP[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameFILTER[Byte1], sizeof(char), 1, pzfHeader);
	for(Byte1 = 0; Byte1 < 16; Byte1++)
		fwrite(&pzfNameOBJ[Byte1], sizeof(char), 1, pzfHeader);
	
	return 0;
}*/



int CreateBLOCK()
{
	short	Sprite;
	char	Draw;
	char	Palette;
	unsigned short ColorTransparent = 0xF81F;
	Block = 1024;
	fwrite(&Block, 2, 1, datBlocks);
	
	for(Block = 0; Block < 1024; Block++)
	{
		fseek(gssSavestate, BLOCKS + (Block << 3), SEEK_SET);
		fread(&Word1, 2, 1, gssSavestate);
		fread(&Word2, 2, 1, gssSavestate);
		fread(&Word3, 2, 1, gssSavestate);
		fread(&Word4, 2, 1, gssSavestate);
		Word1 = (Word1 << 8) + (Word1 >> 8);
		Word2 = (Word2 << 8) + (Word2 >> 8);
		Word3 = (Word3 << 8) + (Word3 >> 8);
		Word4 = (Word4 << 8) + (Word4 >> 8);
		
		priority[Block] = (Word1>>15)+(Word2>>15)+(Word3>>15)+(Word4>>15);
		
		Byte1 = (Word1 >> 15) + ((Word2 >> 15) << 1) + ((Word3 >> 15) << 2) + ((Word4 >> 15) << 3);
		fwrite(&Byte1, 1, 1, datBlockData);

		for(test1 = 0; test1 < 4; test1++)
		{
			if(test1 == 0){
				Sprite = Word1 & 0x7FF;
				Draw = (Word1 >> 11) & 3;
				Palette = (Word1 >> 13) & 3;
			}
			else if(test1 == 1){
				Sprite = Word2 & 0x7FF;
				Draw = (Word2 >> 11) & 3;
				Palette = (Word2 >> 13) & 3;
			}
			else if(test1 == 2){
				Sprite = Word3 & 0x7FF;
				Draw = (Word3 >> 11) & 3;
				Palette = (Word3 >> 13) & 3;
			}
			else{
				Sprite = Word4 & 0x7FF;
				Draw = (Word4 >> 11) & 3;
				Palette = (Word4 >> 13) & 3;
			}


			if(Draw == NORMAL)
			{
				fseek(gssSavestate, SPRITES + (Sprite << 5), SEEK_SET);
				for(test2 = 0; test2 < 8; test2++)
				{
					// PIXEL 1 & 2
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 3 & 4
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 5 & 6
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 7 & 8
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					fseek(datBlocks, 16, SEEK_CUR);
				}
			}
			else if(Draw == MIRROR)
			{
				fseek(gssSavestate, SPRITES + (Sprite << 5) + 3, SEEK_SET);
				for(test2 = 0; test2 < 8; test2++)
				{
					// PIXEL 1 & 2
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 3 & 4
					fseek(gssSavestate, -2, SEEK_CUR);
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 5 & 6
					fseek(gssSavestate, -2, SEEK_CUR);
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 7 & 8
					fseek(gssSavestate, -2, SEEK_CUR);
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					fseek(datBlocks, 16, SEEK_CUR);
					fseek(gssSavestate, 6, SEEK_CUR);
				}
			}
			else if(Draw == FLIP)
			{
				fseek(gssSavestate, SPRITES + (Sprite << 5) + 28, SEEK_SET);
				for(test2 = 0; test2 < 8; test2++)
				{
					// PIXEL 1 & 2
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 3 & 4
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 5 & 6
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 7 & 8
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					fseek(datBlocks, 16, SEEK_CUR);
					fseek(gssSavestate, -8, SEEK_CUR);
				}
			}
			else if(Draw == ROTATE)
			{
				fseek(gssSavestate, SPRITES + (Sprite << 5) + 31, SEEK_SET);
				for(test2 = 0; test2 < 8; test2++)
				{
					// PIXEL 1 & 2
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 3 & 4
					fseek(gssSavestate, -2, SEEK_CUR);
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 5 & 6
					fseek(gssSavestate, -2, SEEK_CUR);
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					// PIXEL 7 & 8
					fseek(gssSavestate, -2, SEEK_CUR);
					fread(&Byte1, 1, 1, gssSavestate);
					Byte2 = (Byte1 & 0xF) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					Byte2 = (Byte1 >> 4) + (Palette << 4);
					if(Byte2 == 0x10 || Byte2 == 0x20 || Byte2 == 0x30 || Byte2 == 0)	Byte2 = 0xFF;
					if(Byte2 != 0xFF){
						Word5 = ((PaletteData[Byte2 * 3] >> 1) << 11)
								| (PaletteData[(Byte2 * 3) + 1] << 5)
								| (PaletteData[(Byte2 * 3) + 2] >> 1);
						fwrite(&Word5, 2, 1, datBlocks);
					}
					else{
						fwrite(&ColorTransparent, 2, 1, datBlocks);
					}
					
					fseek(datBlocks, 16, SEEK_CUR);
					fseek(gssSavestate, -2, SEEK_CUR);
				}
			}

			if(test1 == 0)
				fseek(datBlocks, -240, SEEK_CUR);
			else if(test1 == 1)
				fseek(datBlocks, -16, SEEK_CUR);
			else if(test1 == 2)
				fseek(datBlocks, -240, SEEK_CUR);
			else if(test1 == 3)
				fseek(datBlocks, -16, SEEK_CUR);
		}
	}

	return 0;
}



int CreatePAL()
{
	/*char Header[0x83] =
	{
		0x0A, 0x05, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x48, 0x00,
		0x80, 0x80, 0xFF, 0x10, 0x08, 0x00, 0x10, 0x4A, 0x08, 0x18, 0x08, 0x00, 0x18, 0x39, 0x29, 0x21,
		0x10, 0x00, 0x21, 0x10, 0x08, 0x21, 0x18, 0x08, 0x29, 0x10, 0x00, 0x29, 0x18, 0x00, 0x29, 0x18,
		0x08, 0x29, 0x21, 0x18, 0x31, 0x18, 0x00, 0x31, 0x21, 0x08, 0x31, 0x29, 0x18, 0x39, 0x18, 0x00,
		0x00, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x5E, 0x00, 0x0C
	};*/

	//for(test1 = 0; test1 < 0x83; test1++)
	//	fwrite(&Header[test1], sizeof(char), 1, datPalette);

	fseek(gssSavestate, PALETTE, SEEK_SET);
	Byte4 = 0;

	for(test1 = 0; test1 < 2; test1++)
	{
		// Color 0
		fseek(gssSavestate, 64, SEEK_CUR);	// move to color 0 of third palette
		fread(&Word1, sizeof(Word1), 1, gssSavestate);
		fseek(gssSavestate, -64, SEEK_CUR);	// move to color 1 of first palette
		Byte1 = ((Word1 >> 4) & 0xE0) >> 2;	// Red
		Byte2 = ((Word1 >> 8) & 0xE0) >> 2;	// Green
		Byte3 = (Word1 & 0xE) << 2;			// Blue
		fwrite(&Byte1, sizeof(Byte1), 1, datPalette);
		fwrite(&Byte2, sizeof(Byte2), 1, datPalette);
		fwrite(&Byte3, sizeof(Byte3), 1, datPalette);
		
		// Colors 1-63
		for(test2 = 1; test2 < 64; test2++)
		{
			fread(&Word1, sizeof(Word1), 1, gssSavestate);
			Byte1 = ((Word1 >> 4) & 0xE0) >> 2;	// Red
			Byte2 = ((Word1 >> 8) & 0xE0) >> 2;	// Green
			Byte3 = (Word1 & 0xE) << 2;			// Blue
			fwrite(&Byte1, sizeof(Byte1), 1, datPalette);
			fwrite(&Byte2, sizeof(Byte2), 1, datPalette);
			fwrite(&Byte3, sizeof(Byte3), 1, datPalette);
			if(test1 == 0){
				PaletteData[test2 * 3] = Byte1;
				PaletteData[(test2 * 3) + 1] = Byte2;
				PaletteData[(test2 * 3) + 2] = Byte3;
			}
		}
		
		// Write 64 blank colors
		for(test2 = 0; test2 < 64; test2++)
		{
			fwrite(&Byte4, sizeof(Byte4), 1, datPalette);
			fwrite(&Byte4, sizeof(Byte4), 1, datPalette);
			fwrite(&Byte4, sizeof(Byte4), 1, datPalette);
		}
		
		fseek(gssSavestate, WPALETTE, SEEK_SET);
	}
	
	// Fix transparency color
	PaletteData[0] = PaletteData[96];
	PaletteData[1] = PaletteData[97];
	PaletteData[2] = PaletteData[98];

	return 0;
}



int CreateBMAP()
{
	int		Size;
	
	// =======================================
	// Sonic 1 engine format
	// ---------------------------------------
	// _BPfm_bb bbbbbbbb
	// _NMFE_98 76543210
	// =======================================
	
	// =======================================
	// Sonic 2 engine format
	// ---------------------------------------
	// __BPfmbb bbbbbbbb
	// __NMFE98 76543210
	// =======================================
	
	// =======================================
	// ProSonic engine format
	// ---------------------------------------
	// //uuuuuuup BPtttttt fmbbbbbb bbbbbbbb
	// //VUTSRQPO NMLKJIHG FEDCBA98 76543210
	// ttttttuu uuuLbpBP fmNNNNNN NNNNNNNN
	// (NOTE: little-endian!!)
	// =======================================
	
	fseek(gssSavestate, TILES, SEEK_SET);
	Byte4 = 0;
	
	Size = 16384;
	
	if(Game == SONIC1){
		Byte1 = 3;	// 256x256 (32 << 3)
		fwrite(&Byte1, sizeof(Byte1), 1, datBlockMap);
	}
	else{
		Byte1 = 2;	// 128x128 (32 << 2)
		fwrite(&Byte1, sizeof(Byte1), 1, datBlockMap);
	}
	
	if(Game == SONIC1)
	{
		Word1 = 0;
		for(test1 = 0; test1 < 256; test1++)
			fwrite(&Word1, sizeof(Word2), 1, datBlockMap);
		Size -= 256;
	}
	
	for(test1 = 0; test1 < Size; test1++)
	{
		fread(&Byte1, sizeof(Byte1), 1, gssSavestate);
		fread(&Byte2, sizeof(Byte2), 1, gssSavestate);
		Word1 = (short)((Byte1 << 8) + Byte2);
		//Word1 = ((Word1 >> 8) & 255) + ((Word1 << 8) & 255);	// Byte swap
		//Word2 = Word1 & 0x3FF;				// Block
		DWord1 = Word1 & 0x3FF;					// 11 1111 1111 (b)
		//printf("%04X   ", DWord1);
		//system("pause");
		if(Game == SONIC1){
			////DWord1 += (int)(Word1 & 0x1800) << 3;	// 1 1000 0000 0000 (f and m)
			////DWord1 += (int)(Word1 & 0x6000) << 9;	// 110 0000 0000 0000 (B and P)
			DWord1 += (int)(Word1 & 0x7800) << 3;	// NEW CODE FOR NEW FORMAT!
			DWord1 += (int)(Word1 & 0x6000) << 5;	// NEW CODE FOR NEW FORMAT! (copy BP to bp)
		}
		else{
			////DWord1 += (int)(Word1 & 0xC00) << 4;	// 1100 0000 0000 (f and m)
			//DWord1 += (int)(Word1 & 0x3000) << 10;	// 11 0000 0000 0000 (B and P)
			////DWord1 += (int)(Word1 & 0x2000) << 10;	// 11 0000 0000 0000 (B and P)
			////DWord1 += (int)(Word1 & 0x4000) << 8;	// 11 0000 0000 0000 (B and P)
			DWord1 += (int)(Word1 & 0xFC00) << 4;	// NEW CODE FOR NEW FORMAT!
		}
		
		DWord1 += (int)((int)(priority[Word1 & 0x3FF] > 0)<<20);

		Byte1 = (DWord1 & 0xFF);
		fwrite(&Byte1, sizeof(Byte1), 1, datBlockMap);
		
		Byte1 = ((DWord1 >> 8) & 0xFF);
		fwrite(&Byte1, sizeof(Byte1), 1, datBlockMap);
		
		Byte1 = ((DWord1 >> 16) & 0xFF);
		fwrite(&Byte1, sizeof(Byte1), 1, datBlockMap);
		
		Byte1 = (DWord1 >> 24);
		fwrite(&Byte1, sizeof(Byte1), 1, datBlockMap);
	}
	
	if(Game == SONIC1)
	{
		Word1 = 0;
		Size = 16384;
		for(test1 = 0; test1 < Size; test1++)
			fwrite(&Word1, sizeof(Word2), 1, datBlockMap);
	}

	return 0;
}



int CreateTMAP()
{
	int		Size;
	
	fseek(gssSavestate, MAP, SEEK_SET);
	
	if(Game == SONIC1){
		Size = 1024;
		Byte1 = 0x3F;
		Byte2 = 0x7;
		fwrite(&Byte1, sizeof(Byte1), 1, datTileMap);
		fwrite(&Byte2, sizeof(Byte2), 1, datTileMap);
	}
	else{
		Size = 4096;
		Byte1 = 0x7F;
		Byte2 = 0xF;
		fwrite(&Byte1, sizeof(Byte1), 1, datTileMap);
		fwrite(&Byte2, sizeof(Byte2), 1, datTileMap);
	}
	
	Byte2 = 0;
	for(test1 = 0; test1 < Size; test1++)
	{
		fread(&Byte1, sizeof(Byte1), 1, gssSavestate);
		fwrite(&Byte1, sizeof(Byte1), 1, datTileMap);
		fwrite(&Byte2, sizeof(Byte2), 1, datTileMap);
	}

	return 0;
}



int CreateBSOL()
{
	// Side 0
	fseek(gssSavestate, SOLIDITY, SEEK_SET);

	for(test1 = 0; test1 < 1024; test1++)
	{
		fread(&Byte1, sizeof(Byte1), 1, gssSavestate);

		fseek(datLimp2, Byte1, SEEK_SET);
		fread(&Byte2, sizeof(Byte2), 1, datLimp2);
		fwrite(&Byte2, sizeof(Byte2), 1, datBlockSlope);

		// Floor
		fseek(datLimp2, (Byte1 << 4) + 0x100, SEEK_SET);
		for(test2 = 0; test2 < 16; test2++)
		{
			fread(&Byte2, sizeof(Byte2), 1, datLimp2);
			//Byte2 = 0x10 - Byte2;
			//if(Byte2 > 0x10)
			//	Byte2 += 224;
			fwrite(&Byte2, sizeof(Byte2), 1, datBlockSolid);
		}
		
		// Wall
		fseek(datLimp2, (Byte1 << 4) + 0x1100, SEEK_SET);
		for(test2 = 0; test2 < 16; test2++)
		{
			fread(&Byte2, sizeof(Byte2), 1, datLimp2);
			//Byte2 = 0x10 - Byte2;
			//if(Byte2 > 0x10)
			//	Byte2 += 224;
			fwrite(&Byte2, sizeof(Byte2), 1, datBlockSolid);
		}
	}
	
	// Side 1
	fseek(gssSavestate, SOLIDITY + 0x300, SEEK_SET);

	for(test1 = 0; test1 < 1024; test1++)
	{
		fread(&Byte1, sizeof(Byte1), 1, gssSavestate);

		fseek(datLimp2, Byte1, SEEK_SET);
		fread(&Byte2, sizeof(Byte2), 1, datLimp2);
		fwrite(&Byte2, sizeof(Byte2), 1, datBlockSlope);

		// Floor
		fseek(datLimp2, (Byte1 << 4) + 0x100, SEEK_SET);
		for(test2 = 0; test2 < 16; test2++)
		{
			fread(&Byte2, sizeof(Byte2), 1, datLimp2);
			//Byte2 = 0x10 - Byte2;
			//if(Byte2 > 0x10)
			//	Byte2 += 224;
			fwrite(&Byte2, sizeof(Byte2), 1, datBlockSolid);
		}
		
		// Wall
		fseek(datLimp2, (Byte1 << 4) + 0x1100, SEEK_SET);
		for(test2 = 0; test2 < 16; test2++)
		{
			fread(&Byte2, sizeof(Byte2), 1, datLimp2);
			//Byte2 = 0x10 - Byte2;
			//if(Byte2 > 0x10)
			//	Byte2 += 224;
			fwrite(&Byte2, sizeof(Byte2), 1, datBlockSolid);
		}
	}

	return 0;
}



int CreateOBJ()	// FIX ME!!
{	
	fseek(gssSavestate, VALUE_ZONE, SEEK_SET);
	fread(&Byte1, sizeof(Byte1), 1, gssSavestate);
	fread(&Byte2, sizeof(Byte2), 1, gssSavestate);
	fseek(binROM, 0xE6800 + (Byte1 << 2) + (Byte2 << 1), SEEK_SET);
	fread(&Word1, sizeof(Word1), 1, binROM);
	Word1 = (Word1 >> 8) + (Word1 << 8);
	
	fseek(binROM, 0xE6800 + Word1, SEEK_SET);
	fseek(gssSavestate, RINGS, SEEK_SET);
	
	DWord1 = 0;
	DWord2 = 0;
	Word1 = 0x25;	// Little-endian form of '0x2500' (Ring object)

	while(DWord1 < 0xFFFF0000 && DWord2 < 0xFFFF0000 && Game != SONIC1)	// Temporary solution for Sonic 1
	{
		if(DWord1 < 0xFFFF0000){
			fread(&DWord1, sizeof(DWord1), 1, gssSavestate);
			// Endian conversion
			DWord1 = ((DWord1 & 0xFF000000) >> 24) + ((DWord1 & 0xFF0000) >> 8)
					+ ((DWord1 & 0xFF00) << 8) + ((DWord1 & 0xFF) << 24);
			DWord1 &= 0xFFFF0FFF;
		}
		
		if(DWord2 < 0xFFFF0000){
			fread(&DWord2, sizeof(DWord2), 1, binROM);
			// Endian conversion
			DWord2 = ((DWord2 & 0xFF000000) >> 24) + ((DWord2 & 0xFF0000) >> 8)
					+ ((DWord2 & 0xFF00) << 8) + ((DWord2 & 0xFF) << 24);
			DWord2 &= 0xFFFF0FFF;
		}
		
		while(DWord2 < DWord1){
			fread(&Word4, sizeof(Word4), 1, binROM);
			//if((Word4 & 0xFF) == 3){
				// Endian conversion
				DWord2 = ((DWord2 & 0xFF000000) >> 24) + ((DWord2 & 0xFF0000) >> 8)
						+ ((DWord2 & 0xFF00) << 8) + ((DWord2 & 0xFF) << 24);
				fwrite(&DWord2, sizeof(DWord2), 1, datObjects);
				//Word4 += 8;		// Lower byte is currently 3, so add 8 to make it 0xB
				fwrite(&Word4, sizeof(Word4), 1, datObjects);
				Word1 = 0x25;
				fwrite(&Word1, sizeof(Word1), 1, datObjects);
			//}
			/*else if((Word4 & 0xFF) == 0x11){/////// this code might not be needed //////////////
				// Endian conversion
				DWord2 = ((DWord2 & 0xFF000000) >> 24) + ((DWord2 & 0xFF0000) >> 8)
						+ ((DWord2 & 0xFF00) << 8) + ((DWord2 & 0xFF) << 24);
				fwrite(&DWord2, sizeof(DWord2), 1, datObjects);
				//Word4 += 8;		// Lower byte is currently 3, so add 8 to make it 0xB
				fwrite(&Word4, sizeof(Word4), 1, datObjects);
				Word1 = 0x10;
				fwrite(&Word1, sizeof(Word1), 1, datObjects);
			}*/
			fread(&DWord2, sizeof(DWord2), 1, binROM);
			// Endian conversion
			DWord2 = ((DWord2 & 0xFF000000) >> 24) + ((DWord2 & 0xFF0000) >> 8)
					+ ((DWord2 & 0xFF00) << 8) + ((DWord2 & 0xFF) << 24);
		}
		
		if(DWord2 < 0xFFFF0000)
			fseek(binROM, -4, SEEK_CUR);
				
		// Endian conversion
		DWord1 = ((DWord1 & 0xFF000000) >> 24) + ((DWord1 & 0xFF0000) >> 8)
				+ ((DWord1 & 0xFF00) << 8) + ((DWord1 & 0xFF) << 24);
		
		fwrite(&DWord1, sizeof(DWord1), 1, datObjects);
		fwrite(&Word1, sizeof(Word1), 1, datObjects);
		Word1 = 0;
		fwrite(&Word1, sizeof(Word1), 1, datObjects);
		Word1 = 0x25;
		fseek(gssSavestate, 2, SEEK_CUR);

		// Endian conversion
		DWord1 = ((DWord1 & 0xFF000000) >> 24) + ((DWord1 & 0xFF0000) >> 8)
				+ ((DWord1 & 0xFF00) << 8) + ((DWord1 & 0xFF) << 24);
	}

	//fseek(datObjects, -2, SEEK_CUR);
	//Word1 = 0;
	//fwrite(&Word1, sizeof(Word1), 1, datObjects);
	//fwrite(&Word1, sizeof(Word1), 1, datObjects);
	
	//Byte1 = 0;
	//fseek(datObjects, 0x17FF, SEEK_SET);
	//fwrite(&Byte1, sizeof(Byte1), 1, datObjects);
	

	return 0;
}
